﻿using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System.Collections.Generic;
using System.Reflection;
using PublicClass.CadWatch;

namespace PublicClass
{
    /// <summary>
    /// dll入口,命令定义
    /// </summary>
    public class CmdEntry : IExtensionApplication
    {
        /// <summary>
        /// dll加载 走这里
        /// </summary>
        public void Initialize()
        {
            try
            {
                Assembly.LoadFrom(@"C:\E\GiteeWork\wangafeiblogs\open-class\Day1\Code\bin\PublicTuKu.dll");
                Assembly.LoadFrom(@"C:\E\GiteeWork\wangafeiblogs\open-class\Day1\Code\bin\PublicScreenMenue.dll");
                Assembly.LoadFrom(@"C:\E\GiteeWork\wangafeiblogs\open-class\Day1\Code\bin\PublicTool1.dll");

                Assembly.LoadFrom(@"C:\E\GiteeWork\wangafeiblogs\open-class\Day1\Code\bin\OpenCadNetTool1.dll");
                Assembly.LoadFrom(@"C:\E\GiteeWork\wangafeiblogs\open-class\Day1\Code\bin\OpenCadNetTool2.dll");
            }
            catch (System.Exception e)
            {
                CadUnits.CurEdit().WriteMessage($"加载失败:{e.Message}");
            }
        }
        /// <summary>
        /// dll卸载时处理
        /// </summary>
        public void Terminate()
        {
            CadWatchEntry.ListWatch = null; // 释放所有反应器
        }
        // 第八章 CAD反应器（Document【文档级别的反应器】和 DataBase【数据库反应器】 一一对应）
        // QQ群:529711940 大牛,还有gitee代码 不要有中文(命令名称,C#支持中文函数名)
        /// <summary>
        /// 各种反应器的演示
        /// </summary>
        [CommandMethod("PublicClass_CadWatch")]
        public static void PublicClass_CadWatch()
        {
            CadWatchEntry.ListWatch.Add(new CadApplicationWatch());
            CadWatchEntry.ListWatch.Add(new CadDocumentCollectionWatch());
        }

        // 第二章 拖动类演示之沿路径放置图块
        // QQ群:529711940 大牛,还有gitee代码 不要有中文(命令名称,C#支持中文函数名)
        /// <summary>
        /// 沿路径放置图块
        /// 1.巩固一下曲线相关的函数
        /// 2.巩固一下图块
        /// 3.巩固一下拖动类
        /// </summary>
        [CommandMethod("PublicClass_SetBlkByCurve")]
        public static void PublicClass_SetBlkByCurve()
        {
            // 1.首先有图块,这里用图面选,一般 绿化 放置一些树木/花
            // 2.有路径,这里也是图面上去, 多段线/圆弧/圆等等.
            // 3.拖动类 预览效果,可以动态调整 图块的放置方向
            SetBlkByPathJig.Do();
        }
        // QQ群:529711940 大牛,还有gitee代码 不要有中文(命令名称,C#支持中文函数名)
        [CommandMethod("PublicClass_CoordDimEx")]
        public static void PublicClass_CoordDimEx()
        {
            while (true)
            {
                CoordDimEx jig = new CoordDimEx();
                while (true)
                {
                    PromptPointOptions opt = new PromptPointOptions($"\n指定标注点<{jig.mListDragPt.Count + 1}>:");
                    opt.AllowNone = true;
                    var resPt = CadUnits.CurEdit().GetPoint(opt);
                    if (resPt.Status == PromptStatus.None)
                        break;
                    else if (resPt.Status == PromptStatus.OK)
                    {
                        jig.CoordPt = resPt.Value;
                        jig.mListDragPt.Add(resPt.Value);
                    }
                    else
                        return;
                }

                jig.Prompt = "\n指定标注位置[设置(S)/你好(N)]";
                jig.KeyWordList = "S N";
                jig.Init();
                PromptResult res = CadUnits.CurEdit().Drag(jig);

                if (res.Status == PromptStatus.OK)
                {
                    // 加入数据库
                    jig.AddToDb();
                }
                else if (res.Status == PromptStatus.Keyword)
                {
                    CadUnits.CurEdit().WriteMessage($"输入了关键字{jig.KeyWordUserInput}");
                }
            }
        }

        // QQ群:529711940 大牛,还有gitee代码 不要有中文(命令名称,C#支持中文函数名)
        [CommandMethod("PublicClass_CoordDim")]
        public static void PublicClass_CoordDim()
        {
            while (true)
            {
                var resPt = CadUnits.CurEdit().GetPoint("\n指定标注点:");
                if (resPt.Status != PromptStatus.OK)
                    break;

                CoordDim jig = new CoordDim();
                jig.Prompt = "\n指定标注位置[设置(S)/你好(N)]";
                jig.KeyWordList = "S N";
                jig.CoordPt = resPt.Value;
                PromptResult res = CadUnits.CurEdit().Drag(jig);

                if (res.Status == PromptStatus.OK)
                {
                    // 加入数据库
                    jig.AddToDb();
                }
                else if (res.Status == PromptStatus.Keyword)
                {
                    CadUnits.CurEdit().WriteMessage($"输入了关键字{jig.KeyWordUserInput}");
                }
            }
        }

        // QQ群:529711940 大牛,还有gitee代码
        // 操作系统变量 计算机\HKEY_CURRENT_USER\Software\Autodesk\AutoCAD\R23.1
        [CommandMethod("PublicClass_CadSysVar")]
        public static void PublicClass_CadSysVar()
        {
            // 1.系统变量. 怎么操作,正交.

            CadUnits.SetSystemVariable("ORTHOMODE", 1);
            object obj = CadUnits.GetSystemVariable("ORTHOMODE");
            CadUnits.CurEdit().WriteMessage($"\nORTHOMODE1:{obj}{obj.GetType()}");

            CadUnits.SetSystemVariable("ORTHOMODE", 0);
            obj = CadUnits.GetSystemVariable("ORTHOMODE");
            CadUnits.CurEdit().WriteMessage($"\nORTHOMODE2:{obj}{obj.GetType()}");

            // 2.vs2022 热重载,  不需要重新启动cad就可以完成代码的修改. 1次启动,随便修改代码.
            // 3.如何cad启动时,加载咱们的dll,大家关心 完成
        }


        [CommandMethod("PublicClass_XData")]
        public static void PublicClass_XData()
        {
            List<ObjectId> lst = new List<ObjectId>();
            if (FormTotalEnts.SelectEnts(lst))
            {
                if (lst.Count == 0)
                    return;

                PromptResult res = CadUnits.CurEdit().GetString("\n请输入应用程序名称:");
                string strAppName = res.StringResult;
                if (null == strAppName || strAppName.Length == 0)
                {
                    strAppName = "PublicClass_XDataApp";
                }

                using (Transaction ts = CadUnits.StartTransaction())
                {
                    // 注册引用程序名,不注册,扩展数据写不上去的
                    RegAppTable table = ts.GetObject(CadUnits.CurDb().RegAppTableId, OpenMode.ForWrite) as RegAppTable;
                    if (!table.Has(strAppName))
                    {
                        RegAppTableRecord tableRecord = new RegAppTableRecord();
                        tableRecord.Name = strAppName;

                        table.Add(tableRecord);

                        ts.AddNewlyCreatedDBObject(tableRecord, true);
                    }

                    ResultBuffer rb = new ResultBuffer();
                    rb.Add(new TypedValue((int)DxfCode.ExtendedDataRegAppName, strAppName));
                    rb.Add(new TypedValue((int)DxfCode.ExtendedDataInteger16, 123));
                    rb.Add(new TypedValue((int)DxfCode.ExtendedDataAsciiString, "字符串数据"));

                    ResultBuffer rbXRecord = new ResultBuffer();
                    rbXRecord.Add(new TypedValue((int)DxfCode.XTextString, "字符串数据"));
                    rbXRecord.Add(new TypedValue((int)DxfCode.Int16, 123));

                    foreach (var item in lst)
                    {
                        DBObject obj = ts.GetObject(item, OpenMode.ForWrite);
                        if (null == obj)
                            continue;

                        obj.XData = rb; // 写入扩展数据

                        // 写入扩展记录
                        if (obj.ExtensionDictionary.IsNull)
                        {
                            obj.CreateExtensionDictionary();
                        }

                        DBDictionary dir = ts.GetObject(obj.ExtensionDictionary, OpenMode.ForWrite) as DBDictionary;
                        if (null != dir)
                        {
                            Xrecord xRecord = new Xrecord();
                            xRecord.Data = rbXRecord;
                            ObjectId idRecord = dir.SetAt(strAppName, xRecord);
                            if (!idRecord.IsNull)
                            {
                                ts.AddNewlyCreatedDBObject(xRecord, true);
                            }
                        }

                        //
                    }

                    ts.Commit();
                }
            }
        }
        [CommandMethod("PublicClass_ReadXData")]
        public static void PublicClass_ReadXData()
        {
            List<ObjectId> lst = new List<ObjectId>();
            if (FormTotalEnts.SelectEnts(lst))
            {
                if (lst.Count == 0)
                    return;
                using (Transaction ts = CadUnits.StartTransaction())
                {
                    foreach (var item in lst)
                    {
                        DBObject obj = ts.GetObject(item, OpenMode.ForRead);
                        if (null == obj)
                            continue;

                        if(obj.XData != null)
                        {
                            CadUnits.CurEdit().WriteMessage($"\n实体{item}的扩展数据{obj.XData}");
                        }

                        if (obj.ExtensionDictionary.IsNull)
                            continue;

                        DBDictionary objEx = ts.GetObject(obj.ExtensionDictionary, OpenMode.ForRead) as DBDictionary;
                        if (null != objEx)
                        {
                            foreach (DBDictionaryEntry itemEnt in objEx)
                            {
                                Xrecord objEnt = ts.GetObject(itemEnt.Value, OpenMode.ForRead) as Xrecord;
                                if (null == objEnt)
                                    continue;

                                CadUnits.CurEdit().WriteMessage($"\n实体{item}的扩展记录name:{itemEnt.Key}对应的数据:" +
                                    $"{objEnt.Data}");
                            }

                        }
                    }
                }
            }
        }
        [CommandMethod("PublicClass_EntFun")]
        public static void PublicClass_EntFun()
        {

            List<ObjectId> lst = new List<ObjectId>();
            if (FormTotalEnts.SelectEnts(lst))
            {
                if (lst.Count == 0)
                    return;

                using (Transaction ts = CadUnits.StartTransaction())
                {
                    ObjectId id = lst[0];

                    DBObject obj = ts.GetObject(id, OpenMode.ForRead);
                    if (null == obj)
                        return;

                    // 实体函数
                    Entity ent = obj as Entity;
                    if (null != ent)
                    {
                        // 外包
                        CadUnits.DrawExtent(ts, ent.GeometricExtents);
                        //

                        // 炸开
                        DBObjectCollection entitySet = new DBObjectCollection();
                        ent.Explode(entitySet);
                        foreach (var item in entitySet)
                        {
                            Entity entFor = item as Entity;
                            if (null == entFor)
                                continue;
                            entFor.ColorIndex = (int)CadUnits.ColorEnum.kRed;
                            CadUnits.AppendEntity(ts, entFor);
                        }

                        // 求交
                        if (lst.Count > 1)
                        {
                            ObjectId id2 = lst[1];
                            DBObject obj2 = ts.GetObject(id2, OpenMode.ForRead);

                            Entity ent2 = obj2 as Entity;
                            if (null != ent2)
                            {
                                Point3dCollection points = new Point3dCollection();
                                ent2.IntersectWith(ent, Intersect.OnBothOperands, points, System.IntPtr.Zero, System.IntPtr.Zero);

                                foreach (Point3d item in points)
                                {
                                    CadUnits.CreatCircle(ts, item, 1);
                                }

                                System.Windows.Forms.MessageBox.Show(string.Format("交点个数:{0}", points.Count));
                            }
                        }
                        //
                    }
                    //

                    Curve curve = obj as Curve;
                    if (null != curve)
                    {
                        Point3d pt = Point3d.Origin;

                        Point3d ptClose = curve.GetClosestPointTo(pt, false);
                        CadUnits.CreatCircle(ts, ptClose, 2); // 最近点

                        double dDist = curve.GetDistAtPoint(ptClose);
                        System.Windows.Forms.MessageBox.Show(string.Format("线上距离:{0}", dDist.ToString()));
                    }

                    ts.Commit();
                }
            }
        }

        [CommandMethod("PublicClass_TotalEnts")]
        public static void PublicClass_TotalEnts()
        {
            List<ObjectId> lst = new List<ObjectId>();

            PromptSelectionOptions opt = new PromptSelectionOptions();
            opt.MessageForAdding = "请选择实体";
//             TypedValue[] filer = new TypedValue[1];
//             filer[0] = new TypedValue((int)DxfCode.Start, "CIRCLE");
//             SelectionFilter filerSelect = new SelectionFilter(filer);
            PromptSelectionResult res = CadUnits.CurEdit().GetSelection(opt/*, filerSelect*/);
            if (res.Status == PromptStatus.OK)
            {
                SelectionSet set = res.Value;
                lst.AddRange(set.GetObjectIds());

                CadUnits.CurEdit().WriteMessage("\n选择的实体:{0}个", lst.Count);

                FormTotalEnts form = new FormTotalEnts(lst);
                Application.ShowModalDialog(form);

            }

//             PromptPointResult resPoint = CadUnits.CurEdit().GetPoint("请指定圆心");
//             if (resPoint.Status == PromptStatus.OK)
//             {
//                 Point3d pt = resPoint.Value;
//                 PromptDistanceOptions distOpt = new PromptDistanceOptions("请指定圆半径");
//                 distOpt.UseBasePoint = true;
//                 distOpt.BasePoint = pt;
//                 PromptDoubleResult resDouble = CadUnits.CurEdit().GetDistance(distOpt);
//                 if (resDouble.Status == PromptStatus.OK)
//                 {
//                     using (Transaction ts = CadUnits.StartTransaction())
//                     {
//                         CadUnits.CreatCircle(ts, pt, resDouble.Value);
// 
//                         ts.Commit();
//                     }
//                 }
//             }

        }

        [CommandMethod("PublicClass_CreatEnt")]
        public static void PublicClass_CreatEnt()
        {
            // 创建实体
            Database db = CadUnits.CurDb();
            using (Transaction ts = CadUnits.StartTransaction())
            {
                BlockTable blTable = ts.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord modeSpace = ts.GetObject(blTable[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;

                Line line = new Line();
                line.StartPoint = new Point3d(0, 0, 0);
                line.EndPoint = new Point3d(100, 100, 0);
                string layerName = "cad_line";
                if (CadUnits.CreateLayer(ts, layerName, 1))
                    line.Layer = layerName; // 不给图层,他是默认当前图层

                List<ObjectId> lst = new List<ObjectId>();

                CadUnits.AppendEntity(ts, line, modeSpace); // 加入到模型空间
                lst.Add(line.ObjectId);


                Circle c = new Circle();
                c.Center = new Point3d(0,0,0);
                c.Radius = 50; 
                layerName = "cad_Circle";
                CadUnits.CreateLayer(ts, layerName, (int)CadUnits.ColorEnum.kGreen);
                c.Layer = layerName;
                CadUnits.AppendEntity(ts, c, modeSpace); // 加入到模型空间
                lst.Add(c.ObjectId);

                // 创建块表记录 和 modeSpace同级 
                ObjectId blkRecord = CadUnits.CreatBlk(ts, "测试cad图块创建", lst);

                // 创建块引用  实体 
                BlockReference blk = new BlockReference(new Point3d(100, 100, 0), blkRecord);
                CadUnits.AppendEntity(ts, blk, modeSpace); // 加入到模型空间

                BlockReference blk1 = new BlockReference(new Point3d(1000, 1000, 0), blkRecord);
                CadUnits.AppendEntity(ts, blk1, modeSpace); // 加入到模型空间
                ts.Commit(); // 提交事务
            }
        }

        [CommandMethod("PublicClass_PringMsg")]
        public static void PublicClass_PringMsg()
        {
            Autodesk.AutoCAD.ApplicationServices.Document doc = Application.DocumentManager.MdiActiveDocument;
            doc.Editor.WriteMessage("\n 你好,CAD二次开发!");
        }

        [CommandMethod("PublicClass_SeeEntData")]
        public static void PublicClass_SeeEntData()
        {
            Autodesk.AutoCAD.ApplicationServices.Document doc = Application.DocumentManager.MdiActiveDocument;
            doc.Editor.WriteMessage("\n 查看实体数据");

            ObjectId idSel = ObjectId.Null;

            // 实体的选择,人机交互
            while (true)
            {
                // 支持过滤
                PromptEntityResult res = doc.Editor.GetEntity("\n选择一个实体");
                if (res.Status == PromptStatus.OK)
                {
                    idSel = res.ObjectId;
                    break;
                }
                else if (res.Status == PromptStatus.None || res.Status == PromptStatus.Cancel)
                    return;
                else
                    continue;
            }

            // 实体数据的取法
            // 1.扩展数据. 有专用函数,
            // 2.常规数据. c++中有专门函数的,C#没有找到,调用C++导出(联系我给你提供).类名/图层等.
            // 3.扩展记录. 有专用函数.

            // cad常用的,经常用到,过滤集/扩展数据/还有其他.
            // ResultBuffer buffer = null;
            // DxfCode.SoftPointerId


            EntDataConvertData data = new EntDataConvertData(idSel);

            // 1.界面
            FormSeeEnt dlg = new FormSeeEnt(data);
            Autodesk.AutoCAD.ApplicationServices.Application.ShowModalDialog(dlg);
        }
    }
}
